<template>
	<div class="crop-box">
		<slot :cropperProps="$refs">裁剪控件至少需要一个子元素</slot>
		<input :accept="accept" ref="fileRef" type="file" class="file-input" @change="onFileChange" />
		<el-dialog
			title="图片裁剪"
			width="70%"
			v-loading.fullscreen.lock="loading"
			element-loading-text="正在裁剪..."
			:visible.sync="dialogVisible"
			:append-to-body="true"
			@closed="onDialogClosedHandle"
		>
			<div class="crop-view">
				<div class="crop-main">
					<vue-cropper class="cropper-control" ref="cropper" :aspect-ratio="16 / 9" :src="imgSrc" preview=".preview-area" />
					<div class="text-center mt-20">
						<el-button type="warning" icon="el-icon-folder-opened" @click="reUploadFileHandle">重新上传</el-button>
						<el-button type="info" icon="el-icon-refresh" @click="resetCropHandle">重置裁剪</el-button>
						<el-button type="primary" icon="el-icon-scissors" @click="onCropHandle">确定裁剪</el-button>
					</div>
				</div>
				<div class="crop-aside">
					<p class="preview-label">图片预览 16 / 9</p>
					<div class="preview-area"></div>
				</div>
			</div>
		</el-dialog>
	</div>
</template>

<script>
import { checkLimitSize } from '@/utils/appHead';
import VueCropper from 'vue-cropperjs';
import 'cropperjs/dist/cropper.css';
export default {
	components: {
		VueCropper,
	},
	props: {
		fileType: {
			type: Array,
			default: () => ['gif', 'jpg', 'png'],
		},
		//文件大小限制，默认5M
		limitSize: {
			type: Number,
			default: 5,
		},
	},
	data() {
		return {
			dialogVisible: false,
			loading: false,
			imgSrc: '',
		};
	},
	computed: {
		accept() {
			return this.fileType.map(type => `image/${type}`).join(',');
		},
	},
	methods: {
		//当选择文件时触发
		onFileChange(ev) {
			const aFiles = ev.target.files;
			let selectedFile = null;
			if (aFiles && aFiles.length >= 1) {
				selectedFile = aFiles[0];
			} else {
				selectedFile = null;
			}

			//检测当前浏览器是否支持图片裁剪
			if (!selectedFile) {
				this.$notify.error({
					title: '操作失败',
					message: '当前浏览器不支持图片裁剪功能，请升级浏览器',
				});
				return;
			}

			//检测文件大小
			if (!checkLimitSize(selectedFile, this.limitSize)) {
				this.$notify.error({
					title: '操作失败',
					message: `图片体积过大，建议上传${this.limitSize}M以内的图片`,
				});

				return;
			}

			//设置图片
			this.setImage(selectedFile, () => {
				this.dialogVisible = true;
				this.$nextTick(() => {
					this.$refs.fileRef.value = '';
					this.$refs.cropper.replace(this.imgSrc);
				});
			});
		},

		//设置图片
		setImage(oFile, cb) {
			if (typeof FileReader === 'function') {
				const reader = new FileReader();
				reader.onload = event => {
					this.imgSrc = event.target.result;
					cb && cb(this.imgSrc);
				};
				reader.readAsDataURL(oFile);
			} else {
				this.$notify.error({
					title: '操作失败',
					message: `当前浏览器不支持 FileReader API，请升级浏览器试试~`,
				});
			}
		},

		//重置裁剪弹窗
		resetCropHandle() {
			this.$refs.fileRef.value = '';
			this.$refs.cropper.reset();
		},

		//重新选择文件
		reUploadFileHandle() {
			this.$refs.fileRef.value = '';
			this.$refs.fileRef.click();
		},

		//当dialog完全关闭时触发
		onDialogClosedHandle() {
			this.$refs.fileRef.value = '';
			this.imgSrc = '';
			this.$refs.cropper.destroy();
		},

		//当点击裁剪时触发
		onCropHandle() {
			const cropParams = this.$refs.cropper.getData();
			const formData = new FormData();
			formData.append('x', cropParams.x);
			formData.append('y', cropParams.y);
			formData.append('width', cropParams.width);
			formData.append('height', cropParams.height);
			formData.append('file', this.$refs.fileRef);
			this.loading = true;
		},
	},
};
</script>

<style lang="scss" scoped>
.crop-box {
	display: inline-block;
	vertical-align: middle;
	overflow: hidden;
}
.file-input {
	position: fixed;
	left: -9999px;
	opacity: 0;
	width: 0;
	height: 0;
	font-size: 0;
	line-height: 0;
	opacity: 0;
}
.cropper-control {
	width: 100%;
}
.crop-view {
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: center;
}
.crop-main {
	flex: 1;
}
.crop-aside {
	width: 200px;
	margin-left: 16px;
}

.preview-label {
	width: 100%;
	font-size: 14px;
	color: #666;
	text-align: center;
}
.preview-label {
	margin-bottom: 8px;
}
.preview-area {
	width: 100%;
	height: 140px;
	margin: auto;
	border: 1px dashed #e5e5e5;
	border-radius: 5px;
	overflow: hidden;
	background: url('../assets/images/bg-square.png');
}
</style>
